package cn.datawin.dockerclient.docker;

import com.github.dockerjava.transport.SSLConfig;
import org.apache.hc.core5.ssl.SSLContextBuilder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.PEMDecryptorProvider;
import org.bouncycastle.openssl.PEMEncryptedKeyPair;
import org.bouncycastle.openssl.PEMKeyPair;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
import org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import java.io.FileReader;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.*;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;

public class SecureDockerSSLConfig implements SSLConfig {
	static {
		// 添加 Bouncy Castle 安全提供程序
		Security.addProvider(new BouncyCastleProvider());
	}
    private final String certPath;
    private final String caPassword; // 从配置读取CA私钥密码

    public SecureDockerSSLConfig(String certPath, String caPassword) {
        this.certPath = certPath;
        this.caPassword = caPassword;
    }

    @Override
    public SSLContext getSSLContext() throws KeyManagementException, NoSuchAlgorithmException, KeyStoreException {
        try {
            // 1. 加载CA证书和私钥（需密码）
            X509Certificate caCert = loadCertificate("ca.pem");
            PrivateKey caPrivateKey = loadEncryptedPrivateKey("ca-key.pem", caPassword);

            // 2. 加载客户端证书和私钥
            X509Certificate clientCert = loadCertificate("cert.pem");
            PrivateKey clientPrivateKey = loadPrivateKey("key.pem"); // 未加密

            // 3. 构建完整的证书链（客户端证书 + CA证书）
            Certificate[] certChain = new Certificate[]{clientCert, caCert};

            // 4. 创建密钥库（PKCS12格式）
            KeyStore keyStore = KeyStore.getInstance("PKCS12");
            keyStore.load(null, null);
            keyStore.setKeyEntry(
                "docker-client",  // 别名
                clientPrivateKey,
                "".toCharArray(), // 客户端私钥密码（空）
                certChain         // 完整证书链
            );

            // 5. 创建信任库（仅信任CA证书）
            KeyStore trustStore = KeyStore.getInstance("JKS");
            trustStore.load(null, null);
            trustStore.setCertificateEntry("ca", caCert);

            // 6. 初始化SSLContext（严格模式）
            SSLContext sslContext = SSLContextBuilder.create()
                .setProtocol("TLSv1.2")
                .loadKeyMaterial(keyStore, "".toCharArray())
                .loadTrustMaterial(trustStore, null)
                .build();
			// 禁用主机名验证
			sslContext.getClientSessionContext().setSessionTimeout(0);
			HttpsURLConnection.setDefaultHostnameVerifier((hostname, session) -> true);
            return sslContext;
        } catch (Exception e) {
            throw new RuntimeException("Failed to create SSL context", e);
        }
    }

    // 加载未加密的PEM私钥
    private PrivateKey loadPrivateKey(String filename) throws Exception {
        try (PEMParser parser = new PEMParser(new FileReader(Paths.get(certPath, filename).toFile()))) {
            return new JcaPEMKeyConverter().getPrivateKey(
                ((PEMKeyPair) parser.readObject()).getPrivateKeyInfo()
            );
        }
    }

    // 加载加密的PEM私钥（用于CA私钥）
    private PrivateKey loadEncryptedPrivateKey(String filename, String password) throws Exception {
        try (PEMParser parser = new PEMParser(new FileReader(Paths.get(certPath, filename).toFile()))) {
            PEMEncryptedKeyPair encryptedKeyPair = (PEMEncryptedKeyPair) parser.readObject();
            PEMDecryptorProvider decryptor = new JcePEMDecryptorProviderBuilder()
                .build(password.toCharArray());
            return new JcaPEMKeyConverter().getPrivateKey(
                encryptedKeyPair.decryptKeyPair(decryptor).getPrivateKeyInfo()
            );
        }
    }

    // 加载证书
    private X509Certificate loadCertificate(String filename) throws Exception {
        try (InputStream is = Files.newInputStream(Paths.get(certPath, filename))) {
            return (X509Certificate) CertificateFactory.getInstance("X.509")
                .generateCertificate(is);
        }
    }
}
